#include "stdafx.h"
#include "qxtabcontainer.h"



using namespace micro::gui;

const   int  SPACE_TAB		= 25;
const   int  SPACE_ACTIVE	= 1; //linia de la tabul selectat, laterare suprapuse
const   int  SPACE_LINE		= 3; //linia de la tab-bar 26-
const   int  SPACE_CORNER	= 5;


//XButton
const	int  SPACE_CLOSE	= 18;
const	int  SPACE_BSIZE	= 12;





#define QTAB		_T("TAB")
#define NULL_ITEM   -1



QXTabContainer::QXTabContainer( void )
{
    m_bDrag = false;
    m_dragItem = NULL_ITEM;
    ///m_dragPoint;

    m_closeItem = NULL_ITEM;
    m_closeActive = false;

    m_currentTab = 0;
    m_style = TS_MAXTAB;
    m_bkColor = ::GetSysColor( COLOR_BTNFACE );
}



QXTabContainer::~QXTabContainer( void )
{
    //m_tabList.RemoveAll();

}

void QXTabContainer::SetStyle( UINT style )
{
    m_style = style;
    RecalcLayout();//neceasr pt a aseza clientul

}

void QXTabContainer::SetBkColor( QCOLOR c )
{
    m_bkColor = c;
    Invalidate();
}

bool QXTabContainer::OnSetFocus( HWND hwnd )
{
    int len = m_tabList.GetSize();

    if ( 0 == len )
        return false;

    QTab & ctn =  m_tabList[m_currentTab];
    ctn.pChild->SetFocus();
    return true;
}


bool QXTabContainer::Find( QPanel * p )
{
    int len = m_tabList.GetSize();

    for ( int iCont = 0; iCont < len ; iCont++ )
    {
        QTab & ct =   m_tabList[iCont];

        if ( p == ( QPanel * ) ct.pChild )
            return true;
    }

    return false;
}

UINT QXTabContainer::GetActiveTabID()
{
    QTab & currTab =  m_tabList[m_currentTab];
    return currTab.id;
}

bool QXTabContainer::FindTabByID( int unicid )
{
    int len = m_tabList.GetSize();

    for ( int iCont = 0; iCont < len ; iCont++ )
    {
        QTab & ct =   m_tabList[iCont];

        if ( ct.id == unicid )
        {
            return true;
        }
    }

    return false;
}

void QXTabContainer::RemoveTabByID( int unicid )
{
    int len = m_tabList.GetSize();

    for ( int iCont = 0; iCont < len ; iCont++ )
    {
        QTab & ct =   m_tabList[iCont];

        if ( ct.id == unicid )
        {
            RemoveTab( iCont );
        }
    }

}

void QXTabContainer::SetTabCaptionByID( const QString str , int id )
{
    int len = m_tabList.GetSize();

    for ( int iCont = 0; iCont < len ; iCont++ )
    {
        QTab & ct =   m_tabList[iCont];

        if ( ct.id == id )
        {
            ct.SetCaption( str );
            Invalidate();
        }
    }
}


bool QXTabContainer::OnPreCreate( CREATESTRUCT & cs )
{

    QControl::OnPreCreate( cs );
    cs.style =   WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN;

    return true;
}


bool QXTabContainer::Create( QWindow * parent, int id, UINT style )
{
    m_style = style;
    bool bo = QControl::Create( parent, id, style );
    QLogFont log;
    log.SetMenuFont();
    m_font.Attach( log.CreateFontIndirect() );
    m_pen.CreatePen( PS_SOLID, 1,  ::GetSysColor( COLOR_BTNSHADOW )   );
    //m_theme.OpenThemeData( *this, QTAB );   -- nu e faina culoare de la windows
    return bo;
}
void  QXTabContainer::RemoveTab( QPanel  * p )
{
    int len = m_tabList.GetSize();

    for ( int iCont = 0; iCont < len ; iCont++ )
    {
        QTab & ct =   m_tabList[iCont];

        if ( p ==  ct.pChild )
        {
            RemoveTab( iCont );
            return ;
        }
    }
}
int	QXTabContainer::GetTabCount()
{
    return m_tabList.GetSize();
}
void  QXTabContainer::RemoveTab( int nrTab )
{
    if ( m_tabList.GetSize() <= 1 )
        return;

    QTab  & ct =   m_tabList[nrTab];
    QPanel * tempWin = ct.pChild;
    bool bo = tempWin->ClosePanel();

    if ( false == bo )
        return;

    m_tabList.Remove( nrTab, 1 );

    if ( m_currentTab > 0 )
        if ( m_currentTab >= nrTab )
            m_currentTab = m_currentTab - 1;

    QTab & ctn =  m_tabList[m_currentTab];
    ctn.pChild->Show();
    ctn.pChild->SetFocus();


    RecalcLayout();//neceasr pt a aseza clientul
    OnTabChange();

    delete tempWin;
}

void  QXTabContainer::RemoveAllTabs( )
{

    int len = m_tabList.GetSize();

    for ( int iCont = len - 1; iCont > 0 ; iCont-- )
    {
        QTab & ct =   m_tabList[iCont];

        RemoveTab( iCont );

    }

}


//insert after curent
bool  QXTabContainer::InsertTab( QPanel * pChild, QString str,  UINT id )
{
    ASSERT( pChild );
    bool bo = pChild->Create( this, id );

    if ( !bo )
        return false;

    QTab   tab( pChild, str, id );

    if ( m_tabList.IsEmpty() )
    {
        m_tabList.Add( tab );
        pChild->Show();
        pChild->SetFocus();

        m_currentTab = 0;

    }

    else
    {
        m_tabList.Insert( tab, m_currentTab + 1 );
        pChild->Show();
        pChild->SetFocus();



        QTab & ctn =  m_tabList[m_currentTab];
        ctn.pChild->Hide();

        m_currentTab++;

    }

    RecalcLayout();//neceasr pt a aseza clientul
    OnTabChange();

    return true;
}

bool  QXTabContainer::AddTab( QPanel * pChild, QString str,  UINT id )
{
    ASSERT( pChild );
    bool bo = pChild->Create( this, id );

    if ( !bo )
        return false;

    QTab   tab( pChild, str , id );
    bool empty = m_tabList.IsEmpty();
    m_tabList.Add(  tab );

    if ( empty )
    {
        pChild->Show();
        pChild->SetFocus();


        m_currentTab = 0;
    }
    else
    {
        pChild->Show();
        pChild->SetFocus();


        QTab & ctn =  m_tabList[m_currentTab];
        ctn.pChild->Hide();
    }

    m_currentTab = m_tabList.GetSize() - 1;
    RecalcLayout();//neceasr pt a aseza clientul
    OnTabChange();
    return true;
}



int  QXTabContainer::GetCurrentTab()
{
    return m_currentTab;
}


void QXTabContainer::SetCurrentTabID( int id )
{
    QTab & ctn =  m_tabList[m_currentTab];

    ctn.id = id;

}


void QXTabContainer::SetCurrentTabCaption( const QString str )
{
    QTab & ctn =  m_tabList[m_currentTab];
    ctn.SetCaption( str );
    Invalidate();
}

QWindow  * QXTabContainer::GetCurrentWindow()
{
    return  GetChildWindow( m_currentTab );
}

QWindow  * QXTabContainer::GetChildWindow( int tab )
{
    if ( m_tabList.GetSize() == 0 )
        return nullptr;

    ASSERT( m_tabList.GetSize() > 0 );
    ASSERT( 0 <= tab && tab < m_tabList.GetSize()  );
    QTab & ctn  =  m_tabList[tab];
    return  ctn.pChild;
}

bool QXTabContainer::OnSize( int type, int cx, int cy )
{
    if ( m_tabList.GetSize() )
    {
        RecalcLayout();
    }

    return true;
}

void  QXTabContainer::RecalcLayout()
{
    int nr =  m_tabList.GetSize( );
    ASSERT( nr );

    QRect r = GetClientRect();

    if ( r.IsRectEmpty() )
        return;

    int xx = SPACE_LINE;
    int yy = SPACE_LINE;
    int ww = ( r.Width() - 2 * SPACE_LINE ) /  nr;
    int hh = SPACE_TAB;

    ////for maxSize tabs
    if ( m_style == TS_MAXTAB )
    {
        if ( ww  > MAX_TAB_SIZE )
            ww = MAX_TAB_SIZE;
    }

    r.top = SPACE_TAB;
    r.left ++;
    r.right --;
    r.bottom --;

    for ( int iCont = 0; iCont < m_tabList.GetSize(); iCont++ )
    {
        QTab & ct  =  m_tabList[iCont];
        QWindow * m_tempWin = ct.pChild;

        if ( iCont == m_currentTab )
            ct.rect.SetRect( xx - SPACE_ACTIVE, yy, xx + ww + SPACE_ACTIVE, hh  );
        else
            ct.rect.SetRect( xx, yy, xx + ww, hh  );

        xx += ww;
        m_tempWin->SetWindowPos( nullptr,
                                 r.left,
                                 r.top,
                                 r.Width(),
                                 r.Height(),
                                 SWP_NOACTIVATE
                                 | SWP_NOZORDER
                                 //|SWP_NOCOPYBITS
                                 //|SWP_FRAMECHANGED
                                 //|SWP_NOSENDCHANGING
                                 | SWP_NOREDRAW					////ATENTIE AICI AM SCHIMBAT
                               );
    }

    Invalidate();
}



///////////////////////////////////////////////////////
bool QXTabContainer::OnLButtonDblClk( UINT flags, QPoint & point )
{
    bool onClose = false;
    int item = NULL_ITEM;
    bool onItem = HitTest( point, item, onClose );

    if ( onItem )
    {
        RemoveTab( item );
    }

    return true;
}

QRect QXTabContainer::GetCloseButton( int n )
{
    int nr = m_tabList.GetSize();

    ASSERT( 0 < nr );
    ASSERT( 0 <= n && n < nr );

    QTab & ct =   m_tabList[n];
    QRect rt = ct.rect;


    int x1 = rt.right - SPACE_CLOSE;
    int y1 = rt.top + 4;
    int x2 = x1 + SPACE_BSIZE;
    int y2 = y1 + SPACE_BSIZE;

    return QRect( x1, y1, x2, y2 );
}


bool QXTabContainer::HitTest( const QPoint & pt, int & nItem , bool & onclose  )
{
    onclose = false;
    nItem = NULL_ITEM;
    int nr = m_tabList.GetSize();


    for ( int iCont = 0; iCont < nr; iCont++ )
    {
        QTab & ct =   m_tabList[iCont];

        if (  ct.rect.PtInRect( pt ) )
        {
            nItem = iCont;

            if ( GetCloseButton( iCont ).PtInRect( pt ) )
                onclose = true;

            return true;

        }
    }

    return false;
}

/*

m_whiteBkColor = RGB( 252, 252, 252 ) ; //pentru fundal alb, in lister si editor
m_greyBkColor  = RGB( 240, 240, 240 ); //pt lister bk2, grey



m_buttBackColor		=	RGB( 220, 233, 244 );	 //pt butoane fundal
m_buttBorderColor	=	RGB( 0xcc, 0xcc, 0xcc ); //pt butoane contur



//hot, selected button
m_hotbuttBackColor   = RGB( 207, 230, 253 );	//button back
m_hotbuttBorderColor = RGB( 100, 165, 230 );	//button border

*/


void QXTabContainer::DrawTabs( QGraphics * pdc, int iSel , bool xhover )
{
    if ( ! m_tabList.GetSize() )
        return;

    QRect rcClient	= GetClientRect();
    QRect rcb		= rcClient; //border
    QMemoryGraphics dc( pdc, rcClient );

    //dupa
    rcClient.bottom = SPACE_TAB;
    QSelector sel_2( &dc, m_pen );
    QSelector sel_3( &dc, m_font );
    dc.SetBkMode( TRANSPARENT );
    dc.FillSolidRect( rcClient, m_bkColor );


    QBrush normal(   RGB( 235, 235, 235 )    );
    QBrush hot(  RGB( 227, 240, 253  )   );
    QBrush current(   RGB( 252, 252, 252 )   );

    int round = 4;

    for ( int iCont = 0; iCont < m_tabList.GetSize(); iCont++ )
    {
        if ( iCont == m_currentTab )
        {
            continue;
        }

        QTab & ct =   m_tabList[iCont];
        QRect rc = ct.rect;
        QRect rcx = GetCloseButton( iCont );


        if ( iCont == iSel )
        {
            //hover
            dc.SelectObject( hot );
            //dc.Rectangle( rc );
            dc.RoundRect( rc, round, round );
            DrawXbutton( dc , rcx , xhover );
        }
        else
        {
            //normal
            dc.SelectObject( normal );
            //dc.Rectangle( rc );
            dc.RoundRect( rc, round, round );
            DrawXbutton( dc , rcx , false );
        }

        QRect rt = rc;
        rt.left += 2;
        rt.right -= ( SPACE_CLOSE + 2 );
        dc.DrawText( ct.title, rt, DT_END_ELLIPSIS | DT_VCENTER | DT_CENTER | DT_SINGLELINE );
    }

    //trasare curent tab
    {
        QTab & ct =   m_tabList[m_currentTab];
        QRect rc = ct.rect;

        //curent
        dc.SelectObject( current );
        dc.RoundRect( rc, round, round );

        QRect rt = rc;
        rt.left += 2;
        rt.right -= ( SPACE_CLOSE + 2 );
        dc.DrawText( ct.title, rt, DT_END_ELLIPSIS | DT_VCENTER | DT_CENTER | DT_SINGLELINE );


        QRect rcx = GetCloseButton( m_currentTab );
        DrawXbutton( dc , rcx , xhover && iSel == m_currentTab );
    }


    QRect rr = rcClient;
    rr.top = SPACE_TAB - SPACE_LINE;
    rr.bottom = SPACE_TAB;

    dc.FillSolidRect( rr, ::GetSysColor( COLOR_BTNHIGHLIGHT ) );
    QTab & ct =   m_tabList[m_currentTab];
    dc.MoveTo( 0, SPACE_TAB - SPACE_LINE );
    dc.LineTo( ct.rect.left + 1, SPACE_TAB - SPACE_LINE );
    dc.MoveTo( ct.rect.right - 1, SPACE_TAB - SPACE_LINE );
    dc.LineTo( rcb.right - 1, SPACE_TAB - SPACE_LINE );
    dc.LineTo( rcb.right - 1, rcb.bottom - 1 );
    dc.LineTo( rcb.left, rcb.bottom - 1 );
    dc.LineTo( rcb.left, SPACE_TAB - SPACE_LINE );
}


void QXTabContainer::DrawXbutton( QGraphics & dc , QRect & rcx , bool red )
{
    QCOLOR col = red ? RGB( 170, 74, 78 ) : RGB( 70, 74, 78 );
    QPen pensula( PS_SOLID, 2, col );
    QSelector ss( &dc, pensula );

    if ( red )
    {
        QCOLOR col1 =  RGB( 210, 217, 223 );
        QRect rc = rcx;
        rc.bottom  += 1;
        rc.right   += 1;
        dc.FillSolidRect( rc, col1 );
        rc.left    += 1;
        rc.top     += 1;
        rc.bottom  -= 1;
        rc.right   -= 1;
        dc.FillSolidRect( rc, RGB( 226, 231, 235 ) );
    }


    dc.MoveTo( rcx.left + 3 , rcx.top + 3 );
    dc.LineTo( rcx.right - 3, rcx.bottom - 3 );
    dc.MoveTo( rcx.right - 3 , rcx.top + 3 );
    dc.LineTo( rcx.left + 3, rcx.bottom - 3 );
}




bool QXTabContainer::OnMouseLeave()
{
    Invalidate();
    StopTrackEvents();
    return true;
}

void  QXTabContainer::RedrawTabs( int sel, bool xhover )
{

    QClientGraphics cdc( this );
    QRect rc	= GetClientRect();
    QMemoryGraphics dc( &cdc, rc );
    DrawTabs( &dc,  sel, xhover );

}

bool QXTabContainer::OnMouseMove( UINT flags, QPoint & point )
{
    if ( m_closeActive )
    {
        return true;
    }

    if ( m_bDrag )
    {
        int deltax =  ( point.x - m_dragPoint.x );

        QRect rc = m_tabList[m_dragItem].rect;

        int cx = rc.left;
        int rcw = rc.Width();
        int rch = rc.Height();

        rc.OffsetRect( deltax, 0 );
        //try intersect

        QRect inter;


        //block left
        if ( rc.left <= SPACE_LINE )
        {
            //deltax = -rc.left + SPACE_LINE;
            m_tabList[m_dragItem].rect.OffsetRect( -cx + SPACE_LINE, 0 );
            RedrawTabs( m_dragItem, false );
            return true;
        }

        int wx = GetClientRect().Width();

        ///block right
        if ( rc.right >= wx - SPACE_LINE )
        {
            m_tabList[m_dragItem].rect.right = wx - SPACE_LINE - 1;
            m_tabList[m_dragItem].rect.left = wx - SPACE_LINE - 1 - rcw;
            RedrawTabs( m_dragItem, false );
            return true;
        }

        m_tabList[m_dragItem].rect.OffsetRect( deltax, 0 );

        m_dragPoint = point;
        bool cond = false;

        if ( cond )
        {
            ///Slide one tab
            RedrawTabs( m_dragItem, false );
        }
        else
            RedrawTabs( m_dragItem, false );



        return true;
    }

    //hover
    bool onClose = false;
    int item = NULL_ITEM;
    bool onItem = HitTest( point, item, onClose );

    if ( onItem )
    {
        RedrawTabs( item , onClose );
    }

    if ( ! IsTracking() )
    {
        TrackMouseEvents( this );
    }

    return true;
}

bool QXTabContainer::OnLButtonDown( UINT flags, QPoint & point )
{
    //1 - daca e pe X closeActive
    //2 - daca e pe tab, dar nu si pe x   se focuseaza/selecteaza
    // 3- agatare
    //

    int nr =  m_tabList.GetSize();

    ASSERT( nr );

    if ( nr <= 1 )
        return true;

    bool onClose = false;
    int item = NULL_ITEM;
    bool onItem = HitTest( point, item, onClose );

    if ( onClose )
    {
        m_closeActive = true;
        m_closeItem = item;
        //desenare eventual
        SetCapture();
        return true;
    }


    if ( onItem )// garantat fara onClose
    {
        if ( item != m_currentTab )
        {
            QTab & ct1 =   m_tabList[item];
            QWindow * win1 = ct1.pChild;

            QTab & ct2 =   m_tabList[m_currentTab];
            QWindow * win2 = ct2.pChild;
            win1->Show();
            win2->Hide();
            win1->SetFocus();


            m_currentTab = item;
            //RecalcLayout();//neceasr pt a reface dreptunghiul focusat
            OnTabChange();
        }

        //agatare
        m_bDrag = true;
        m_dragItem = item;
        m_dragPoint = point;
        SetCapture();
    }

    return true;
}

bool QXTabContainer::OnLButtonUp( UINT flags, QPoint & point )
{
    //
    bool onClose = false;
    int item = NULL_ITEM;
    bool onitem = HitTest( point , item , onClose );

    if ( m_closeActive )
    {
        if ( onClose &&  m_closeItem == item )
        {
            RemoveTab( item );
            m_closeItem = NULL_ITEM;
            m_closeActive = false;
        }
        else
        {
            m_closeItem = NULL_ITEM;
            m_closeActive = false;
        }
    }


    if ( m_bDrag )
    {
        ///slide item to new pozition


        m_bDrag = false;
        m_dragItem = NULL_ITEM;
        m_dragPoint.SetPoint( 0, 0 );

    }


    ReleaseCapture();
    return true;
}


bool  QXTabContainer::OnEraseBackground( QGraphics * pdc )
{
    if ( m_tabList.GetSize() )
        return true;

    //picteaza ceva fundal
    return false;
}
bool  QXTabContainer::OnPaint( QGraphics * pdc )
{
    DrawTabs( pdc );
    return true;
}


void QXTabContainer::MoveNextTab( bool next )
{
    int nrtabs = m_tabList.GetSize();

    if ( nrtabs  <= 1 )
        return ;

    int inext = 0;

    if  ( next )
        inext =   ( m_currentTab + 1 ) % nrtabs;

    else
    {
        inext = m_currentTab - 1;

        if ( inext < 0 )
            inext = nrtabs - 1;
    }

    SetActiveTab( inext );
}

void  QXTabContainer::SetActiveTabByID( int unicid )
{
    int nrtabs = m_tabList.GetSize();

    for ( int iCont = 0; iCont < nrtabs  ; iCont++ )
    {
        QTab & ct =   m_tabList[iCont];

        if ( ct.id == unicid &&  iCont != m_currentTab )
        {
            QWindow * win2 = ct.pChild;
            QTab & ct2 =   m_tabList[m_currentTab];
            QWindow * win1 = ct2.pChild;
            win2->Show();
            win1->Hide();
            win2->SetFocus();


            m_currentTab = iCont;
            RecalcLayout();
            OnTabChange();
            break;
        }
    }
}


void QXTabContainer::SetActiveTab( int tab )
{
    if ( tab == m_currentTab )
        return;

    ASSERT( tab >= 0 );
    ASSERT ( tab <  m_tabList.GetSize() );


    QTab & ct2 =   m_tabList[m_currentTab];
    QWindow * win2 = ct2.pChild;
    QTab & ct1 =   m_tabList[tab];
    QWindow * win = ct1.pChild;
    win->Show();
    win2->Hide();
    win->SetFocus();
    m_currentTab = tab;
    RecalcLayout();
    OnTabChange();

}
